﻿

// ## 2023/11/11 # 铃 # 当大城市受到攻击,有兵力,有兵装但是没有人的时候,附近据点如果有人可用,会像这个城市支援武将.

namespace AI城市紧急调度
{

	const int 召唤城市距离 = 1;

	/// =========================================================================================

	const bool 调试模式 = false;
	const bool 调试模式2 = false;
	const int KEY = pk::hash("AI城市紧急调度");

	class Main
	{

		Main()
		{
			pk::bind(202, pk::trigger202_t(onAIRunningOrder));
		}

		void onAIRunningOrder(pk::ai_context @context, pk::building @building, int cmd)
		{
			if (cmd == 据点AI_紧急调度)
			{
				pk::force @force = pk::get_force(building.get_force_id());
				pk::ai_context_base @base = context.base[building.get_id()];

				// 由于查询指令相对来说比较消耗计算能力,因此要能跳过的全都在主要赋值之前跳过,减少计算
				//紧急调度不涉及玩家,也不需要用军团,255中玩家不触发紧急调度

				// 战斗中才执行
				if (base.status != 据点状态_战斗)
					return;

				if (!base.enemies_around3)
					return;

				// 敌人不多就退出
				if (base.num_enemy_units < 3)
					return;

				// 如果是玩家城市,就退出
				if (building.is_player())
					return;

				// 如果耐久所剩不多,就不需要调度了
				if (int(building.hp) < int(pk::get_max_hp(building) * 0.5) and building.hp < 3000)
					return;

				// 如果只有一个据点就不用了
				if (ch::get_base_list(force).count == 1)
					return;

				int src_id = -1;
				int 召唤人数 = 0;
				int 可用人数 = base.num_idle_officers;
				int 总兵装含战马 = pk::get_weapon_amount(building, 1) + pk::get_weapon_amount(building, 2) + pk::get_weapon_amount(building, 3) + pk::get_weapon_amount(building, 4);
				int 己方可用战斗兵力 = pk::min(building.troops, int(总兵装含战马 * 0.85));
				pk::int_int 据点周边兵力 = ch::base_range_self_and_enemy_troops(building, 5);
				int 据点境内敌方兵力 = 据点周边兵力.second; 
				int 己方已出征兵力 = 据点周边兵力.first; 
				int 还需出征兵力 = int(pk::max(0, 据点境内敌方兵力 - 己方已出征兵力) * 1.5);
				int 所需武将数 = 还需出征兵力 / 5000 + 1;
				int 有效兵力能支持的武将数 = 己方可用战斗兵力 / 5000;

				// 判断城市的可用人数,有人可用则不需要召唤
				if (可用人数 > 3)
					return;

				// 获取距离1以内的,人数最多城市.
				// 距离为1 主要是为了防止在路上的人没有被计入小城,重复操作导致.
				// 未来再考虑距离为2,路上的问题
				src_id = get_best_base(building);

				// 如果获取不到则退出.
				if (src_id == -1)
					return;

				auto idle_person_list = pk::get_idle_person_list(pk::get_building(src_id));
				auto person_list = pk::get_person_list(pk::get_building(src_id), pk::mibun_flags(身份_君主, 身份_都督, 身份_太守, 身份_一般));
				int 预留人数 = ch::when_suppor_calc_reserve_person_count(src_id, idle_person_list, person_list);

				if (building.get_id() == 城市_襄阳 and 调试模式2)
					pk::trace(pk::format("7src_id ：{},person_list.count：{},idle_person_list.count：{},来源据点预留人数 ：{},召唤人数：{},", src_id, person_list.count, idle_person_list.count, 预留人数, 召唤人数));

				// 再次确认人数
				if (idle_person_list.count == 0)
					return;
				if (person_list.count < 3)
					return;

				召唤人数 = pk::min(person_list.count - 预留人数, 所需武将数, idle_person_list.count, 有效兵力能支持的武将数) + 1;
				召唤人数 = pk::max(召唤人数, 1);

				if (building.get_id() == 城市_襄阳 and 调试模式2)
					pk::trace(pk::format("8己方可用战斗兵力：{},据点境内敌方兵力：{},己方已出征兵力：{},来源据点预留人数 ：{},召唤人数：{},有效兵力能支持的武将数:{},", 己方可用战斗兵力, 据点境内敌方兵力, 己方已出征兵力, 预留人数, 召唤人数, 有效兵力能支持的武将数));

				// 按照能力最低来排序
				idle_person_list.sort(function(a, b) {
					return (a.stat[武将能力_统率] + a.stat[武将能力_武力] + a.stat[武将能力_智力]) > (b.stat[武将能力_统率] + b.stat[武将能力_武力] + b.stat[武将能力_智力]);
				});

				// 召唤对象武将

				pk::list<pk::person @> actors;
				int j = 0;
				for (int i = 0; i < idle_person_list.count; i++)
				{

					if (pk::is_absent(person_list[i]) or pk::is_unitize(person_list[i]))
						continue;
					if (person_list[i].action_done == true)
						continue;
					if (person_list[i].order == 武将任务_移动)
						continue;
					j++;
					actors.add(person_list[i]);
					person_list[i].action_done = true;
					string person_name2 = pk::format("\x1b[1x{}\x1b[0x", pk::decode(pk::get_name(person_list[i])));

					if (调试模式)
					{
						string person_name = pk::format("\x1b[1x{}\x1b[0x", pk::decode(pk::get_name(person_list[i])));
						string building_name = pk::format("\x1b[1x{}\x1b[0x", pk::decode(pk::get_name(building)));
						string dst_name = pk::format("\x1b[1x{}\x1b[0x", pk::decode(pk::get_name(pk::get_building(src_id))));
						string action_message = pk::format("{}从{}召唤了{}", building_name, dst_name, person_name);
						pk::trace(pk::format("{}从{}召唤了{}", building_name, dst_name, person_name));
					}
					if (j >= 召唤人数)
						break;
				}

				// 召唤命令
				pk::summon_cmd_info cmd_summon;
				@cmd_summon.base = building;
				cmd_summon.actors = actors;
				pk::command(cmd_summon);

				ch::remove_idle_person(context, actors);
			}
			return;
		}

		int get_best_base(pk::building @dst)
		{
			pk::list<pk::building @> list;

			for (int i = 0; i < 据点_末; i++)
			{
				pk::building @src = pk::get_building(i);

				// 如果选到自己就跳过
				if (dst.get_id() == i)
					continue;

				// 如果距离太远就跳过
				if (pk::get_building_distance(dst.get_id(), i, dst.get_force_id()) > 召唤城市距离)
					continue;

				// 如果不同势力就跳过
				if (dst.get_force_id() != src.get_force_id())
					continue;

				// 如果除了君主之外的人数小于3个就跳过
				auto src_person_list = pk::get_person_list(src, pk::mibun_flags(身份_都督, 身份_太守, 身份_一般));
				auto src_idle_person_list = pk::get_idle_person_list(src);

				// 如果小城市召唤人数不够,则跳过
				if (src_idle_person_list.count < ch::when_suppor_calc_reserve_person_count(i, src_idle_person_list, src_person_list))
					continue;

				// 大城市人不能太少
				// if (src_idle_person_list.count < ch::when_suppor_calc_reserve_person_count(i))
					//continue;

				if (ch::enemy_troop_base_near_distance(src, 5) == 0)
					list.add(src);
			}

			if (list.count > 0)
			{

				// 排序的标准是:人越多分越高,距离近的分高,小城市分高
				list.sort(function(a, b) {
					int stat_a = pk::get_idle_person_list(a).count * 5 + ((a.get_id() < 城市_末) ? 0 : 20);
					int stat_b = pk::get_idle_person_list(b).count * 5 + ((b.get_id() < 城市_末) ? 0 : 20);
					return (stat_a > stat_b);
				});

				return (list[0].get_id());
			}
			else
				return -1;
		}

	} Main main;
}